// 手写节流函数

/**
 * 执行频率：在事件频繁触发时，以固定的时间间隔执行
 * 
 * 应用场景：页面滚动、鼠标移动、窗口调整大小等高频事件
 * 
 * 目的：限制执行频率，降低函数调用的次数
 */

/**
 * 创建一个节流函数，在给定的时间间隔内最多执行一次目标函数
 * @param {function} func - 需要节流的目标函数
 * @param {number} intervalTime - 节流的间隔时间（毫秒）
 * @param {Object} [options] - 节流的配置选项
 * @param {boolean} [options.leading = true] - 是否在第一次调用时立即执行
 * @param {boolean} [options.trailing = false] - 是否在冷却时间结束后追加一次执行
 * @param {function} [options.resultCallback] - 每次节流函数执行后的回调函数，用于处理目标函数的返回值
 * @return {function} - 返回包装后的节流函数 
 * @author m
 * @example
 *
 * ```js
 * // 创建一个节流函数，每 1000 毫秒最多执行一次
 * const throttledFn = throttle(() => {
 *   console.log('Throttled function executed');
 * }, 1000);
 * 
 * // 绑定事件
 * document.addEventListener('scroll', throttledFn);
 * 
 * // 调用 cancel 方法
 * throttledFn.cancel();
 * ```
 * 
 */

function throttle(func, intervalTime = 200, options = { leading: true, trailing: false, resultCallback }) {
  // 记录上一次的开始时间
  const { leading, trailing, resultCallback } = options;
  // 每次点击时，重置当前最新时间
  let lastTime = 0;
  // 记录
  let timer = null;

  const _throttle = function (...args) {
    // 获取"第一次"调用时间
    let nowTime = new Date().getTime();
    // 必须第一次执行(lastTime) 且 用户传参调节为首次不立即执行(leading)
    if (!lastTime && !leading) lastTime = nowTime;
    // 获取冷却时间 = 节流间隔时间 - 第一次响应时间 + 发起响应时间
    const remainTime = intervalTime - nowTime + lastTime;

    // 达到冷却，可以执行响应函数
    if (remainTime <= 0) {
      // 如果节流间隔后存在正常响应函数,将"最后一次响应函数"的定时器清除
      if (timer) {
        clearTimeout(timer);
        timer = null;
      }
      const result = func.apply(this, args);
      // 返回值
      if (resultCallback) resultCallback(result);
      // 记录函数上一次被成功调用的时间戳
      lastTime = nowTime;
      return;
    }

    // 节流最后一次也可以执行的判断逻辑
    if (trailing && !timer) {
      // 返回timer,只有冷却归零后还未存在正常调用,timer尚未清零才能调用,一旦调用则重置timer
      timer = setTimeout(() => {
        timer = setTimeout(() => {
          timer = null;
          lastTime = !leading ? 0 : new Date().getTime();
          const result = func.apply(this, args);
          // 返回值
          if (resultCallback) resultCallback(result);
        })

      }, remainTime);
    }
  }

  // 取消方法
  _throttle.cancel = function () {
    // 有值的情况才进行取消
    if (timer) clearTimeout(timer);
    // 初始化
    timer = null;
    lastTime = 0;
  }

  return _throttle;
}